package tr.gen._3bit.java._2k1s.api;

import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.NoSuchPortException;
import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import gnu.io.UnsupportedCommOperationException;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import tr.gen._3bit.java._2k1s.api.exception.DeviceIsBusyException;
import tr.gen._3bit.java._2k1s.api.exception.NotASerialPortException;
import tr.gen._3bit.java._2k1s.dao.model.SerialInterface;

public class SerialComm {

	private Boolean _available = true;
	private InputStream in = null;
	private OutputStream out = null;
	private short bufferSize = 32;
	private SerialPort serialPort = null;

	public SerialComm() {
		super();
	}

	public void connect(SerialInterface serialInterface) throws NoSuchPortException,
			PortInUseException, UnsupportedCommOperationException, IOException,
			NotASerialPortException {
		CommPortIdentifier portIdentifier = CommPortIdentifier
				.getPortIdentifier(serialInterface.getPort());

		CommPort commPort = portIdentifier
				.open(this.getClass().getName(), 2000);

		if (commPort instanceof SerialPort) {
			serialPort = (SerialPort) commPort; 
			serialPort.setSerialPortParams(serialInterface.getBaudrate(), 
					serialInterface.getDatabits(),
					serialInterface.getStopbits(), 
					serialInterface.getParity());

			in = serialPort.getInputStream();
			out = serialPort.getOutputStream();

		} else {
			throw new NotASerialPortException(serialInterface.getLabel()
					+ " is not a serial port");
		}

	}

	public short getBufferSize() {
		return bufferSize;
	}

	public void setBufferSize(short bufferSize) {
		this.bufferSize = bufferSize;
	}

	private Boolean get_available() {
		return _available;
	}

	private void set_available(Boolean _available) {
		this._available = _available;
	}

	private void wait_available() throws InterruptedException,
			DeviceIsBusyException {
		wait_available((short) 10);
	}

	private void wait_available(short count) throws InterruptedException,
			DeviceIsBusyException {
		if (!get_available()) {
			while (!get_available()) {
				Thread.sleep(1);
				if (count > 10)
					throw new DeviceIsBusyException();
				else
					count++;
			}
		}
	}

	public void write(String str) throws IOException, DeviceIsBusyException {
		for (char c : str.toCharArray())
			write((int) c);
	}

	public void write(int c) throws IOException, DeviceIsBusyException {

		try {
			wait_available();
			set_available(false);
			out.write(c);

			Thread.sleep(5);

			set_available(true);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	public byte[] read() throws DeviceIsBusyException, IOException {
		byte[] buffer = null;
		try {
			wait_available();
			set_available(false);

			buffer = new byte[getBufferSize()];
			if (in.available() > 0)
				in.read(buffer);

			Thread.sleep(1);

			set_available(true);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return buffer;
	}

	public void close() throws IOException {
		if (serialPort != null) {

			serialPort.close();
			serialPort = null;
		}
		if (!get_available()) {
			if (in != null)
				in.close();
			if (out != null) // this used to be serialPort.close
				out.close();
		}
	}

}